package com.qixiaobao.common.utils.easyExcel;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.read.listener.PageReadListener;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * easyExcel 工具类
 *
 * @author yangxm
 */
public class EasyExcelUtil {

    /**
     * 使用 模型 来读取Excel
     *
     * @param inputStream Excel的输入流
     * @param clazz       模型的类
     * @return 返回 模型 的列表
     */
    public static <T> List<T> readExcel(InputStream inputStream, Class<T> clazz) {
        ModelExcelListener<T> listener = new ModelExcelListener<T>();
        EasyExcel.read(inputStream, clazz, listener).sheet().doRead();
        return listener.getDatas();
    }

    /**
     * 读取 Excel 文件，返回 List<Map<String, String>>
     *
     * @param filePath Excel 文件路径
     * @return 每一行对应一个 Map<列索引, 值>
     */
    public static List<Map<Integer, String>> read(String filePath) {
        return read(filePath, 1);
    }

    /**
     * 读取 Excel 文件，返回 List<Map<String, String>>
     *
     * @param filePath Excel 文件路径
     * @param headRowNumber 表头所在行号（从0开始）
     * @return 每一行对应一个 Map<列索引, 值>
     */
    public static List<Map<Integer, String>> read(String filePath, int headRowNumber) {
        File file = new File(filePath);
        if (!file.exists()) {
            throw new RuntimeException("文件不存在: " + filePath);
        }
        return doRead(file, headRowNumber);
    }

    // 内部方法 - 使用自定义监听器收集结果并过滤空行
    private static List<Map<Integer, String>> doRead(File file, int headRowNumber) {
        List<Map<Integer, String>> result = new CopyOnWriteArrayList<>();
        EasyExcel.read(file)
                .headRowNumber(headRowNumber)
                .sheet()
                .registerReadListener(new PageReadListener<Map<Integer, String>>(dataList -> {
                    for (Map<Integer, String> row : dataList) {
                        if (isValidRow(row)) {
                            Map<Integer, String> cleanedRow = new HashMap<>();
                            for (Map.Entry<Integer, String> entry : row.entrySet()) {
                                String value = entry.getValue();
                                // 去除所有空白字符（包括空格、换行、制表符等）
                                String cleanedValue = (value != null) ? value.replaceAll("\\s+", "") : null;
                                cleanedRow.put(entry.getKey(), cleanedValue);
                            }
                            result.add(cleanedRow);
                        }
                    }
                }))
                .doRead();
        return result;
    }

    /**
     * 通过输入流读取 Excel，返回 List<Map<String, String>>
     *
     * @param inputStream Excel 输入流
     * @return 每一行对应一个 Map<列索引, 值>
     */
    public static List<Map<Integer, String>> read(InputStream inputStream) {
        return read(inputStream, 1);
    }

    /**
     * 通过输入流读取 Excel，返回 List<Map<String, String>>
     *
     * @param inputStream Excel 输入流
     * @param headRowNumber 表头所在行号（从0开始）
     * @return 每一行对应一个 Map<列索引, 值>
     */
    public static List<Map<Integer, String>> read(InputStream inputStream, int headRowNumber) {
        return doRead(inputStream, headRowNumber);
    }

    // 内部方法 - 使用自定义监听器收集结果并过滤空行
    private static List<Map<Integer, String>> doRead(InputStream inputStream, int headRowNumber) {
        List<Map<Integer, String>> result = new CopyOnWriteArrayList<>();
        EasyExcel.read(inputStream)
                .headRowNumber(headRowNumber)
                .sheet()
                .registerReadListener(new PageReadListener<Map<Integer, String>>(dataList -> {
                    for (Map<Integer, String> row : dataList) {
                        if (isValidRow(row)) {
                            Map<Integer, String> cleanedRow = new HashMap<>();
                            for (Map.Entry<Integer, String> entry : row.entrySet()) {
                                String value = entry.getValue();
                                // 去除所有空白字符（包括空格、换行、制表符等）
                                String cleanedValue = (value != null) ? value.replaceAll("\\s+", "") : null;
                                cleanedRow.put(entry.getKey(), cleanedValue);
                            }
                            result.add(cleanedRow);
                        }
                    }
                }))
                .doRead();
        return result;
    }

    /**
     * 判断是否为有效行（非空且至少有一个非空字段）
     */
    private static boolean isValidRow(Map<Integer, String> row) {
        if (row == null || row.isEmpty()) {
            return false;
        }
        return row.values().stream().anyMatch(val -> val != null && !val.trim().isEmpty());
    }



    /**
     * 使用 动态表头 来导出到WEB
     *
     * @param response      web的响应
     * @param data         要写入的数据集合
     * @param fileName     配置Excel的表名
     * @param sheetName    配置Excel的页签名
     * @param headList     动态表头
     * @throws IOException
     */
    public static <T> void writeExcel(HttpServletResponse response, List<T> data, List<List<String>> headList, String fileName, String sheetName) throws IOException {
        // 这里注意 有同学反应使用swagger 会导致各种问题，请直接用浏览器或者用postman
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        fileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        EasyExcel.write(response.getOutputStream()).head(headList).registerWriteHandler(new ExcelWidthStyleStrategy()).sheet(sheetName).doWrite(data);
    }

    /**
     * 使用 模型 来导出到WEB
     *
     * @param response      web的响应
     * @param data         要写入的以 模型 为单位的数据
     * @param fileName     配置Excel的表名
     * @param sheetName    配置Excel的页签名
     * @param clazz        模型的类
     * @throws IOException
     */
    public static <T> void writeExcel(HttpServletResponse response, List<T> data, Class<T> clazz, String fileName, String sheetName) throws IOException {
        // 这里注意 有同学反应使用swagger 会导致各种问题，请直接用浏览器或者用postman
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        fileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        EasyExcel.write(response.getOutputStream(), clazz).sheet(sheetName).doWrite(data);
    }

    /**
     * 使用 模型 来写入Excel
     * <br/>注意，如果是web输出流，需要设置头
     *
     * @param outputStream Excel的输出流
     * @param data         要写入的以 模型 为单位的数据
     * @param sheetName    配置Excel的表名字
     * @param clazz        模型的类
     */
    public static <T> void writeExcel(OutputStream outputStream, List<T> data, Class<T> clazz, String sheetName) {
        EasyExcel.write(outputStream, clazz).sheet(sheetName).doWrite(data);
    }

    /**
     * 模型 解析监听器
     */
    private static class ModelExcelListener<T> extends AnalysisEventListener<T> {
        private List<T> datas = new ArrayList<>();

        @Override
        public void invoke(T object, AnalysisContext context) {
            datas.add(object);
        }

        @Override
        public void doAfterAllAnalysed(AnalysisContext context) {
        }

        public List<T> getDatas() {
            return datas;
        }
    }

    public static void main(String[] args) {
        String filePath = "C:\\Users\\Summer\\Downloads\\导入保单号模板_20240313.xlsx";
        List<Map<Integer, String>> list = EasyExcelUtil.read(filePath, 0);
        System.out.println(list);
    }
}
